What Do You Understand About Dependency Injection in C#?

Dependency Injection (DI) is a design pattern used in software development to achieve loose coupling between objects and their dependencies. In simple terms, it allows you to inject dependencies (services, objects, or classes) into a class, rather than having the class create or manage those dependencies itself. This makes the code more flexible, testable, and easier to maintain. 

This improves modularity, testability, and maintainability of code by reducing tight coupling between classes.

In simpler terms, Dependency Injection allows an object to receive its dependencies from the outside world, making the class easier to manage and test.

Key Concepts of Dependency Injection

Dependency:

A dependency is an object or service that a class needs to function. For example, if a Car class relies on an Engine class to operate, the Engine is a dependency of the Car.

Injection:

The process of supplying the dependencies to a class from an external source is called "injection." Instead of a class creating its dependencies, they are "injected" into the class, usually via constructors, properties, or methods.

Types of Dependency Injection

There are three main types of dependency injection:

Constructor Injection:

Dependencies are provided to a class through its constructor. This is the most common and preferred method in many frameworks.

Example:

	

public class Car

{

    private readonly IEngine _engine;

    // Constructor injection

    public Car(IEngine engine)

    {

        _engine = engine;

    }

    public void Drive()

    {

        _engine.Start();

        Console.WriteLine("Car is driving...");

    }

}


Property Injection (Setter Injection):

Dependencies are provided through property setters after the object is created.

Example:

	

public class Car

{

    public IEngine Engine { get; set; }

    public void Drive()

    {

        Engine.Start();

        Console.WriteLine("Car is driving...");

    }

}


Method Injection:

Dependencies are passed directly to a method as parameters, allowing for fine-grained control over the lifecycle of the dependency.

Example:


public class Car

{

    public void Drive(IEngine engine)

    {

        engine.Start();

        Console.WriteLine("Car is driving...");

    }

}


Benefits of Dependency Injection


Loose Coupling:


By injecting dependencies, the class does not need to know the details about how its dependencies are created or configured. This makes it easier to swap out different implementations of dependencies (e.g., mock objects in unit testing).

Improved Testability:


Dependency Injection makes unit testing easier because you can inject mock objects or stubs instead of real dependencies, allowing you to isolate and test individual classes in isolation.

Flexibility:


It allows you to change or configure dependencies at runtime. For example, you can inject different logging services depending on whether the application is in development or production.

Maintainability:


Dependency Injection simplifies code maintenance by centralizing the configuration and management of dependencies.

Real-Life Example of Dependency Injection in WPF Application Using Prism Framework


In WPF applications, Prism is a popular framework that implements the MVVM (Model-View-ViewModel) design pattern. It supports dependency injection through the use of Unity or Autofac containers.

Let’s consider an example where we want to implement dependency injection in a simple WPF application using Prism and the Unity Container to inject services into a ViewModel.

Step 1: Setting Up Prism and Unity


First, you need to install the required NuGet packages for Prism.Unity.

This package allows you to use the Unity container for dependency injection in a Prism-based WPF application.

Step 2: Define a Service Interface and Implementation


Let’s assume we have a service that provides logging functionality. This service will be injected into our ViewModel.

public interface ILoggerService  
{
    void Log(string message);
}
  
public class LoggerService : ILoggerService
{
    public void Log(string message)
    {
        // Log message to console for simplicity
        Console.WriteLine($"Log: {message}");
    }
}

Step 3: Creating the ViewModel


In our ViewModel, we want to use the ILoggerService to log messages. Rather than directly creating an instance of LoggerService, we’ll use Dependency Injection to provide it.

  
using Prism.Mvvm;
public class MainWindowViewModel : BindableBase
{
    private readonly ILoggerService _logger;
    public MainWindowViewModel(ILoggerService loggerService)
    {
        _logger = loggerService;
        _logger.Log("MainWindowViewModel initialized.");
    }
}

Notice that the ILoggerService is injected through the constructor.

Step 4: Configuring the Unity Container in App.xaml.cs


In a Prism WPF application, you typically set up the DI container in the App.xaml.cs file by registering the services and configuring the ViewModels.

  
using Prism.Ioc;
using Prism.Unity;
using System.Windows;
namespace DependencyInjectionExample
{
    public partial class App : PrismApplication
    {
        protected override Window CreateShell()
        {
            return Container.Resolve<MainWindow>();
        }
        protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
          // Register the ILoggerService to be injected wherever needed
            containerRegistry.Register<ILoggerService, LoggerService>();
        }
    }
}

Here, we are registering the ILoggerService and mapping it to the LoggerService implementation. When MainWindowViewModel asks for an ILoggerService, the Unity container will inject an instance of LoggerService.

Step 5: Using the ViewModel in MainWindow


Finally, we bind the MainWindowViewModel to MainWindow using Prism’s ViewModel locator.

  
<Window x:Class="DependencyInjectionExample.MainWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Dependency Injection Example" Height="200" Width="400">
    <Grid>
        <TextBlock Text="Check Console for Log Output" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Window>

Post a Comment

0 Comments